package controller

import (
	"fmt"
	"github.com/gin-gonic/contrib/sessions"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	"io"
	"mynetdisk/model"
	"mynetdisk/utils"
	"net/http"
	"net/url"
	"os"
	"path"
	"strconv"
	"strings"
	"time"
)

/**
 *@Author tudou
 *@Date 2019/8/24
 **/

func DownloadByName(c *gin.Context) {
	finalPath := c.PostForm("finalPath")
	username := c.PostForm("username")
	session := sessions.Default(c)
	user := session.Get("username").(string)
	userId := session.Get("user").(uint)
	paths := strings.LastIndex(finalPath, "/")
	name := finalPath[paths+1:]
	rePath := finalPath[:paths+1]
	var f model.File
	var reUser model.User
	if !reUser.GetUserByName(username) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "the user is not existed"})
		return
	}
	if !utils.DirExisted(rePath, userId) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "please input the right path"})
		return
	}
	if strings.Contains(finalPath, ".") {
		c.JSON(http.StatusBadRequest, gin.H{"error": "please input the right path"})
		return
	}
	if !utils.FileExisted(rePath, name) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "the file is not existed"})
		return
	}
	//首先判断该文件你是否有权限
	if !f.GetFileByFinalPath(name,rePath,reUser.Id){
		c.JSON(http.StatusOK,gin.H{"error":"there is an unknown error"})
		return
	}
	if username != user {
		if f.Uid != 0 {
			c.JSON(http.StatusOK, gin.H{"error": "you don't have power download"})
			return
		}
	}
	finalPath = StaticPath + utils.ParseUintToString(reUser.Id) + finalPath
	c.Header("Content-Disposition", "attachment;filename="+url.QueryEscape(path.Base(name)))
	c.Header("Content-Description", "File Transfer")
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Transfer-Encoding", "binary")
	c.Header("Expires", "0")
	c.Header("Cache-Control", "must-revalidate")
	c.Header("Pragma", "public")
	c.File(finalPath)
	//c.JSON(http.StatusOK,gin.H{"message":"downloading successfully"})
}

func DownloadByPassword(c *gin.Context) {
	password := c.PostForm("password")
	uuId := c.Param("uuid")
	reUuid, _ := uuid.FromString(uuId)
	var f model.FileShare
	if !f.GetShareFile(reUuid) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "the file is not existed"})
		return
	}
	if f.Password != password {
		c.JSON(http.StatusOK, gin.H{"message": "the password is wrong"})
		return
	}
	//首先判断是否过期
	//再判断时否为一次性即若为0的话则证明是一次性下载链接
	nowTime := utils.ParseTime(time.Now())
	if utils.CompareTime(f.Timeout, nowTime) {
		c.JSON(http.StatusOK, gin.H{"message": "the link can't use"})
		return
	}
	var ff model.File
	if !ff.GetFile(f.Uid) {
		c.JSON(http.StatusOK, gin.H{"message": "the file is not existed"})
		return
	}
	finalPath := StaticPath + utils.ParseUintToString(ff.Uid) + ff.Location + ff.Name
	c.Header("Content-Disposition", "attachment;filename="+url.QueryEscape(path.Base(ff.Name)))
	c.Header("Content-Description", "File Transfer")
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Transfer-Encoding", "binary")
	c.Header("Expires", "0")
	c.Header("Cache-Control", "must-revalidate")
	c.Header("Pragma", "public")
	if f.DownloadNum == 0 {
		f.DeleteShareFile()
	}
	f.AddShareFileNum()
	c.JSON(http.StatusOK, gin.H{"message": "downloading successfully"})
	c.File(finalPath)

}

func DownloadByRandom(c *gin.Context) {
	uuId := c.Param("uuid")
	reUuid, _ := uuid.FromString(uuId)
	//判断此记录是否存在
	var f model.FileShare
	if !f.GetShareFile(reUuid) {
		c.JSON(http.StatusOK, gin.H{"message": "the link can't use"})
		return
	}
	//首先判断此链接是否超过时间
	nowTime := utils.ParseTime(time.Now())
	if utils.CompareTime(f.Timeout, nowTime) {
		c.JSON(http.StatusOK, gin.H{"message": "the link can't use"})
		return
	}
	//判断file里面此文件是否还存在
	var ff model.File
	if !ff.GetFile(f.Uid) {
		c.JSON(http.StatusOK, gin.H{"message": "the file is not existed"})
		return
	}
	finalPath := StaticPath + utils.ParseUintToString(ff.Uid) + ff.Location + ff.Name
	c.Header("Content-Disposition", "attachment;filename="+url.QueryEscape(path.Base(ff.Name)))
	c.Header("Content-Description", "File Transfer")
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Transfer-Encoding", "binary")
	c.Header("Expires", "0")
	c.Header("Cache-Control", "must-revalidate")
	c.Header("Pragma", "public")
	if f.DownloadNum == 0 {
		f.DeleteShareFile()
	}
	f.AddShareFileNum()
	c.File(finalPath)
	c.JSON(http.StatusOK, gin.H{"message": "downloading successfully"})
}

func DownloadByPoint(c *gin.Context) {
	r := c.Request
	w := c.Writer
	uuId := c.Param("uuid")
	reUuid, _ := uuid.FromString(uuId)
	var f model.FileShare
	if !f.GetShareFile(reUuid) {
		c.JSON(http.StatusOK, gin.H{"message": "the link can't use"})
		return
	}
	nowTime := utils.ParseTime(time.Now())
	if utils.CompareTime(f.Timeout, nowTime) {
		c.JSON(http.StatusOK, gin.H{"message": "the link can't use"})
		return
	}
	var ff model.File
	if !ff.GetFile(f.Uid) {
		c.JSON(http.StatusOK, gin.H{"message": "the file is not existed"})
		return
	}
	var start, end int64
	fmt.Sscanf(r.Header.Get("Range"), "bytes=%d-%d", &start, &end)
	rePath := StaticPath + utils.ParseUintToString(ff.Uid) + ff.Location + ff.Name
	file, err := os.Open(rePath)
	if err != nil {
		utils.CheckErr(err, "open the file failed")
		c.JSON(http.StatusNotFound, gin.H{"error": "there is an unknown error"})
		return
	}
	info, err := file.Stat()
	if err != nil {
		utils.CheckErr(err, "file stat failed")
		c.JSON(http.StatusNotFound, gin.H{"error": "there is an unknown error"})
		return
	}
	if start < 0 || start >= info.Size() || end < 0 || end >= info.Size() {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(fmt.Sprintf("out of index, length:%d", info.Size())))
		return
	}
	if end == 0 {
		end = info.Size() - 1
	}
	w.Header().Add("Accept-ranges", "bytes")
	w.Header().Add("Content-Length", strconv.FormatInt(end-start+1, 10))
	w.Header().Add("Content-Range", "bytes "+strconv.FormatInt(start, 10)+"-"+strconv.FormatInt(end, 10)+"/"+strconv.FormatInt(info.Size()-start, 10))
	w.Header().Add("Content-Disposition", "attachment; filename="+info.Name())
	_, err = file.Seek(start, 0)
	if err != nil {
		utils.CheckErr(err, "the file seek failed")
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	_, err = io.CopyN(w, file, end-start+1)
	if err != nil {
		utils.CheckErr(err, "the file copy failed")
		return
	}
}
